#include "../../include/Reactor/ThreadPool.h"
#include <unistd.h>

ThreadPool::ThreadPool(size_t threadNum, size_t queSize) 
: m_threads()
, m_cache(50)
, m_threadNum(threadNum)
, m_queSize(queSize)
, m_que(m_queSize)
, m_isExit(false)
{

}

ThreadPool::~ThreadPool() {

}

//线程池启动
void ThreadPool::start() {
    for(size_t idx = 0; idx < m_threadNum; ++idx)
    {
        MyThread *myThread{new MyThread{(int)idx, 4, this}};
        myThread->th = std::thread{&ThreadPool::doTask, this, myThread};
        m_threads.push_back(myThread);
    }
}

//关闭线程池
void ThreadPool::stop() {
    //主线程执行stop函数时不应该轻易地改变标志位
    //如果发现任务队列不为空，说明还有任务没有执行完
    while(!m_que.empty())
    {
        sleep(1);
    }

    //修改标志位，表示线程池要退出
    m_isExit = true;

    //需要将threadPool声明为TaskQueue的友元类
    /* m_que.m_notEmpty.notify_all(); */
    m_que.wakeup();
    
    //让主线程等待子线程退出
    for(auto & thread : m_threads)
    {
        // th.join();
        thread->th.join();
    }
}

void ThreadPool::addTask(ElemType && ptask) {
    //因为如果出现空指针调用虚函数的情况
    //一定会发生段错误，所以做一个检查
    if(ptask)
    {
        m_que.push(std::move(ptask)); 
#ifdef DEBUG
    cout << "已将任务添加至队列" << endl;
#endif
    }
}

//从TaskQueue中获取任务
ElemType ThreadPool::getTask() {
    return m_que.pop(); 
}

//doTask被注册为工作线程的入口函数
void ThreadPool::doTask(MyThread* myTh) {
    //只要线程池不退出，就应该让工作线程一直执行任务
    while(!m_isExit){
        //如果任务队列为空，就让工作线程阻塞
        ElemType ptask = getTask();

        if(ptask)
        {

#ifdef DEBUG
            cout << "开始执行任务" << endl;
#endif
            
            ptask(myTh);
        }
        else
        {
            cout << "ptask == nullptr" << endl;
        }
    }
}
